(*
 *    _  _   ____                         _  
 *  _| || |_/ ___|  ___ _ __  _ __   ___ | | 
 * |_  ..  _\___ \ / _ \ '_ \| '_ \ / _ \| | 
 * |_      _|___) |  __/ |_) | |_) | (_) |_| 
 *   |_||_| |____/ \___| .__/| .__/ \___/(_) 
 *                     |_|   |_|             
 *
 * Personal Social Web.
 *
 * Copyright (C) The #Seppo contributors. All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *)

open Seppo_lib
open Alcotest

let set_up () =
  Mirage_crypto_rng_unix.use_default ();
  Unix.chdir "../../../test/"

(*
let cp' ?(buf = 16 * 0x400 |> Bytes.create) src oc =
  let ic = open_in_gen [ Open_rdonly; Open_binary ] 0 src in
  ic |> copy_channel ~buf oc;
  close_in ic
*)

let tc_www_base () =
  (match
     "/a/b/c"
     |> String.split_on_char '/'
     |> List.rev
     |> List.cons "."
   with
   | [ d; c; b; a; v ] ->
     v |> Assrt.equals_string __LOC__ "";
     a |> Assrt.equals_string __LOC__ "a";
     b |> Assrt.equals_string __LOC__ "b";
     c |> Assrt.equals_string __LOC__ "c";
     d |> Assrt.equals_string __LOC__ ".";
   | _ ->
     "woring" |> Assrt.equals_string __LOC__ "");
  (match
     "/a/b/c"
     |> String.split_on_char '/'
     |> List.rev
     |> File.find_path_tail (fun s -> Ok (s |> String.equal "/b/c"))
   with
   | Ok s -> s |> Assrt.equals_string __LOC__ "/b/c"
   | Error e -> e |> Assrt.equals_string __LOC__ "");
  let wefi u =
    let wkwf =  ".well-known/webfinger/" in
    let i = u |> Uri.path |> String.split_on_char '/' |> List.length in
    ((List.init (i-2) (fun _ -> "../") |> String.concat "") ^ wkwf)
  in
  "https://ursi@demo.mro.name/" |> Uri.of_string
  |> wefi |> Assrt.equals_string __LOC__ ".well-known/webfinger/";
  "https://ursi@demo.mro.name/seppo/" |> Uri.of_string
  |> wefi |> Assrt.equals_string __LOC__ "../.well-known/webfinger/"

module Path = struct
  let tc_climb () =
    let u = Uri.make ~scheme:"https" ~userinfo:"foo" ~host:"example.com" ~path:"/a/b/c/" () in
    u |> Uri.path |> Assrt.equals_string __LOC__ "/a/b/c/";
    let i = u |> Uri.path |> String.split_on_char '/' |> List.length in
    List.init (i-2) (fun _ -> "..") |> String.concat "/"
    |> Assrt.equals_string __LOC__ "../../..";
    "z" |> Assrt.equals_string __LOC__ "z"

  let tc_hd_tl () =
    "/foo/bar/baz"
    |> File.Path.hd '/'
    |> Option.get |> Assrt.equals_string __LOC__ "";
    let t0 = "/foo/bar/baz" |> File.Path.tl '/' |> Option.get in
    t0 |> Assrt.equals_string __LOC__ "foo/bar/baz";
    t0 |> File.Path.hd '/'
    |> Option.get |> Assrt.equals_string __LOC__ "foo";
    let t1 = t0 |> File.Path.tl '/' |> Option.get in
    t1 |> Assrt.equals_string __LOC__ "bar/baz";
    let t2 = t1 |> File.Path.tl '/' |> Option.get in
    t2 |> Assrt.equals_string __LOC__ "baz";
    assert (t2 |> File.Path.tl '/' |> Option.is_none);
    assert true
end

let tc_out_channel_atomic () =
  "tmp/a.txt" |> File.out_channel_append (fun oc -> output_string oc "huhu");
  "tmp/b.txt" |> File.out_channel_replace (fun oc -> output_string oc "huhu");
  "tmp/c.txt" |> File.out_channel_replace ~mode:[Open_binary;Open_creat;Open_excl;Open_trunc;Open_wronly] (fun oc -> output_string oc "huhu");
  "" |> Assrt.equals_string __LOC__ ""

let e = epsilon_float

let tc_touch () =
  check (float e) "NaN is NaN" nan nan;
  "-" |> check string __LOC__ "-";
  let t0 = Unix.time () in
  let fn = "data/touch" in
  let t = fn |> File.mtime_0 in
  t0 -. t > 1. |> check bool __LOC__ true;
  fn |> File.touch;
  let t = fn |> File.mtime_0 in
  t -. t0 >= 0. |> check bool __LOC__ true;
  t -. t0 < 1. |> check bool __LOC__ true

let () =
  run
    "seppo_suite" [
    __FILE__ , [
      "set_up",                `Quick, set_up;
      "tc_www_base",           `Quick, tc_www_base;
      "Path.tc_climb",         `Quick, Path.tc_climb;
      "Path.tc_hd_tl",         `Quick, Path.tc_hd_tl;
      "tc_out_channel_atomic", `Quick, tc_out_channel_atomic;
      "tc_touch",              `Quick, tc_touch;
    ]
  ]
